#include "ds18b20_driver.h"

void DS18B20_IO_IN(DS18B20_HandleTypeDef* hds18b20)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = hds18b20->DQ_Pin;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(hds18b20->DQ_GPIO_Port, &GPIO_InitStructure);
}

void DS18B20_IO_OUT(DS18B20_HandleTypeDef* hds18b20)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = hds18b20->DQ_Pin;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(hds18b20->DQ_GPIO_Port, &GPIO_InitStructure);
}

void DS18B20_Rst(DS18B20_HandleTypeDef* hds18b20)
{
    DS18B20_IO_OUT(hds18b20);
    HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_RESET);
    delay_us(750);
    HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_SET);
    delay_us(15);
}

uint8_t DS18B20_Check(DS18B20_HandleTypeDef* hds18b20)
{
    uint8_t retry = 0;
    DS18B20_IO_IN(hds18b20);
    while (HAL_GPIO_ReadPin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin) && retry < 200)
    {
        retry++;
        delay_us(1);
    }
    if (retry >= 200)
        return 1;
    else
        retry = 0;
    while (!HAL_GPIO_ReadPin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin) && retry < 240)
    {
        retry++;
        delay_us(1);
    }
    if (retry >= 240)
        return 2;
    return 0;
}

void DS18B20_Write_Byte(DS18B20_HandleTypeDef* hds18b20, uint8_t data)
{
    uint8_t j;
    uint8_t databit;
    DS18B20_IO_OUT(hds18b20);
    for (j = 1; j <= 8; j++)
    {
        databit = data & 0x01;
        data = data >> 1;
        if (databit)
        {
            HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_RESET);
            delay_us(2);
            HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_SET);
            delay_us(60);
        }
        else
        {
            HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_RESET);
            delay_us(60);
            HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_SET);
            delay_us(2);
        }
    }
}

uint8_t DS18B20_Read_Bit(DS18B20_HandleTypeDef* hds18b20)
{
    uint8_t data;
    DS18B20_IO_OUT(hds18b20);
    HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_RESET);
    delay_us(4);
    HAL_GPIO_WritePin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin, GPIO_PIN_SET);
    DS18B20_IO_IN(hds18b20);
    if (HAL_GPIO_ReadPin(hds18b20->DQ_GPIO_Port, hds18b20->DQ_Pin))
        data = 1;
    else
        data = 0;
    delay_us(50);
    return data;
}

uint8_t DS18B20_Read_Byte(DS18B20_HandleTypeDef* hds18b20)
{
    uint8_t i, j, data;
    data = 0;
    for (i = 1; i <= 8; i++)
    {
        j = DS18B20_Read_Bit(hds18b20);
        data = (j << 7) | (data >> 1);
    }
    return data;
}

void DS18B20_Start(DS18B20_HandleTypeDef* hds18b20)
{
    DS18B20_Rst(hds18b20);
    DS18B20_Check(hds18b20);
    DS18B20_Write_Byte(hds18b20, 0xcc); // 跳过ROM
    DS18B20_Write_Byte(hds18b20, 0x44); // 温度变换命令
}

uint8_t DS18B20_Init(DS18B20_HandleTypeDef* hds18b20)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = hds18b20->DQ_Pin;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(hds18b20->DQ_GPIO_Port, &GPIO_InitStructure);
    DS18B20_Rst(hds18b20);
    return DS18B20_Check(hds18b20);
}

short DS18B20_Get_Temperature(DS18B20_HandleTypeDef* hds18b20)
{
    uint8_t temp;
    uint8_t TL, TH;
    short temperature;
    DS18B20_Start(hds18b20);
    DS18B20_Rst(hds18b20);
    DS18B20_Check(hds18b20);

    DS18B20_Write_Byte(hds18b20, 0xcc); // 跳过ROM
    DS18B20_Write_Byte(hds18b20, 0xbe); // 读暂存器
    TL = DS18B20_Read_Byte(hds18b20); // 低八位
    TH = DS18B20_Read_Byte(hds18b20); // 高八位

    if (TH > 0x70)
    {
        TH = ~TH;
        TL = ~TL;
        temp = 0;
    }
    else
        temp = 1;
    temperature = TH;
    temperature <<= 8;
    temperature += TL;
    temperature = (float)temperature * 0.625;
    if (temperature)
        return temperature;
    else
        return -temperature;
}
